package model;

import java.util.ArrayList;
import java.util.Queue;

public class Node {
	static float MIN_SCORE = -99999;
	static float MAX_SCORE = 99999;

	public ArrayList<Node> children;
	private float localScore;
	private Board board;
	private Move previousMove;
	private int currentDepth;

	Node(Move move, Board board, int depth) {
		children = null;
		this.board = board;
		localScore = Engine.evaluate(board);
		currentDepth = depth;
		previousMove = move;
	}
	
	public int getDepth() {
		return currentDepth;
	}

	public boolean isLeave() {
		if (children == null) return true;
		return (children.size() == 0);
	}
	
	public boolean isCreatedChildren() {
		return (children != null) ;
	}

	/**
	 * Create children on level N-1
	 * @param nodeQueue Refence of node stack to feed
	 */
	public void createChildren(Queue<Node> nodeQueue) {
		if (children == null) {
			children = new ArrayList<Node>();
			ArrayList<Move> possibleMoves = Engine.getLegalMoves(board);
			for (Move move : possibleMoves) {
				Board childBoard = new Board(board);
				childBoard.Play(move);
				Node child = new Node(move, childBoard, this.getDepth()+1);
				children.add(child);
				nodeQueue.offer(child);
			}
		}
	}
	
	public float getScore() {
		return alphaBeta(MIN_SCORE, MAX_SCORE);		
	}

	private float alphaBeta(float alpha, float beta) {
		if (this.isLeave()) {
			return this.localScore;
		} else {
			float best = MIN_SCORE;
			for (Node child : children) {
				float Val = -child.alphaBeta(-beta, -alpha);
				if (Val > best) {
					best = Val;
					if (best > alpha) {
						alpha = best;
						if (alpha >= beta) {
							return best;
						}
					}
				}
				return best;
			}
			return beta;
		}
	}

	public Move getPreviousMove() {
		return previousMove;
	}
	
	public String toString(){
		String depth = "depth=" + getDepth();
		if(isLeave())return depth + " leave node";
		if(children.size()>0) return depth + " node with " + children.size() + " children";
		return "node";
	}
}
